package com.fang.study.watch;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @author fanglingxiao
 * @version 1.0
 * @description TODO
 * @date 2022/7/7 12:43 下午
 **/
public class LockCallbackWatch implements Watcher, AsyncCallback.StringCallback,
        AsyncCallback.Children2Callback,
        AsyncCallback.StatCallback {
    private final ZooKeeper zk;
    private final CountDownLatch cdl = new CountDownLatch(1);
    private final String threadName;
    private String pathName;

    public LockCallbackWatch(ZooKeeper zooKeeper, String threadName) {
        this.zk = zooKeeper;
        this.threadName = threadName;
    }

    public void tryLock() {
        try {
            // 节点创建之后 由StringCallback回调
            // todo 可重入 getData获取锁记录判断是否同一个线程
            System.out.println(threadName + ".....start create.....");
            zk.create("/lock", threadName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, this, "abc");
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * StringCallback回调
     */
    @Override
    public void processResult(int rc, String path, Object ctx, String name) {
        System.out.println("----StringCallback回调,name=" + name + "----");
        if (name == null) {
            return;
        }
        pathName = name;
        zk.getChildren("/", false, this, "gsdf");
    }

    /**
     * children callback
     */
    @Override
    public void processResult(int i, String s, Object o, List<String> children, Stat stat) {
        // 一定可以看到前面已创建的节点
        // 由于获取的children非有序
        Collections.sort(children);
        // 因为pathName有一个 /
        int index = children.indexOf(pathName.substring(1));
        if (index == 0) {
            try {
                System.out.println("i am first....");
                zk.setData(pathName,threadName.getBytes(),-1);
            } catch (KeeperException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            cdl.countDown();
        } else {
            zk.exists("/" + children.get(index - 1), this, (StatCallback) this, "adsf");
        }
    }

    public void unLock() {
        try {
            zk.delete(pathName, -1);
            System.out.println(threadName + " unLock...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
        switch (watchedEvent.getType()) {
            case None:
                break;
            case NodeCreated:
                break;
            case NodeDeleted:
                zk.getChildren("/", false, this, "gsdf");
                break;
            case NodeDataChanged:
                break;
            case NodeChildrenChanged:
                break;
            default:
        }

    }

    @Override
    public void processResult(int i, String s, Object o, Stat stat) {
        // todo
    }
}
